#include <rtc_base/logging.h>

#include "base/socket.h"
#include "base/async_udp_socket.h"
#include "async_udp_socket.h"

namespace xrtc {

const size_t MAX_BUF_SIZE = 1500;

void async_udp_socket_io_cb(EventLoop* /*el*/, IOWatcher* /*w*/, int fd, int events, void* data)  {
    AsyncUdpSocket* udp_socket = (AsyncUdpSocket*)data;
    if (EventLoop::READ & events) {
        udp_socket->recv_data();
    }

    if (EventLoop::WRITE & events) {
        udp_socket->send_data();
    }
}


AsyncUdpSocket::AsyncUdpSocket(EventLoop *ev, int socket) : m_ev(ev), m_socket(socket), 
                                                            m_buf(new char[MAX_BUF_SIZE]),   
                                                            m_size(MAX_BUF_SIZE) {
    m_socket_watcher = m_ev->createIOEvent(async_udp_socket_io_cb, this);
    m_ev->startIOEvent(m_socket_watcher, m_socket, EventLoop::READ);
}

AsyncUdpSocket::~AsyncUdpSocket() {
    if (m_socket_watcher) {
        m_ev->deleteIOEvent(m_socket_watcher);
        m_socket_watcher = nullptr;
    }

    if (m_buf) {
        delete[] m_buf;
        m_buf = nullptr;
    }
}

void AsyncUdpSocket::recv_data() {
    while (true) {
        struct sockaddr_in addr;
        socklen_t addr_len = sizeof(addr);
        int len = sock_recv_from(m_socket, m_buf, m_size, (struct sockaddr*)&addr, addr_len);
        if (len <= 0) {
            return ;
        }

        char ip_str[INET_ADDRSTRLEN]; // 确保缓冲区足够大
        const char* result = inet_ntop(AF_INET, &(addr.sin_addr), ip_str, INET_ADDRSTRLEN);
        if (result != nullptr) {
            RTC_LOG(LS_INFO) << "recv address: " << ip_str;
        } else {
            RTC_LOG(LS_ERROR) << "IP address conversion failed";
        }

        RTC_LOG(LS_INFO) << "recv port: " << ntohs(addr.sin_port);


        // 获取数据包到达服务器的时间
        int64_t ts = sock_get_recv_timestamp(m_socket);
        // 获取NAT映射的反射地址
        int port = ntohs(addr.sin_port);
        char ip[64] = {0};
        inet_ntop(AF_INET, &addr.sin_addr, ip, sizeof(ip));

        rtc::SocketAddress remote_addr(ip, port); // 反射地址

        // 发出推流端数据包读取完成的信号
        signal_read_packet(this, m_buf, len, remote_addr, ts);
    }
}

// 遍历 m_udp_packet_list 队列，发送UDP数据包
void AsyncUdpSocket::send_data() {
    size_t len = 0;
    int ret = 0;
    while (!m_udp_packet_list.empty()) {
        // 处理任务队列中的UDP数据包
        UdpPacketData* packet = m_udp_packet_list.front();
        // m_udp_packet_list.pop_front();
        sockaddr_storage addr;
        len = packet->get_addr().ToSockAddrStorage(&addr);
        ret = sock_send_to(m_socket, packet->get_data(), packet->get_size(), MSG_NOSIGNAL, (struct sockaddr*)(&addr), len);
        if (ret < 0) {
            RTC_LOG(LS_WARNING) << "send udp packet error, error: " << strerror(errno) << ", errno: " << errno
                                << ", remote_addr: " << packet->get_addr().ToString();

            delete packet;
            m_udp_packet_list.pop_front();
            return ;
        } else if (ret == 0) {
            RTC_LOG(LS_WARNING) << "send 0 bytes, try again, remote_addr: " << packet->get_addr().ToString();
            return ;
        } else {
            delete packet;
            m_udp_packet_list.pop_front();
        }
    }

    // UDP数据包为空，数据发送完成，停止对UDP数据包发送事件的监听
    if (m_udp_packet_list.empty()) {
        m_ev->startIOEvent(m_socket_watcher, m_socket, EventLoop::WRITE);
    } 
}

int AsyncUdpSocket::send_to(const char *data, size_t size, const rtc::SocketAddress &addr) {
    return _add_udp_packet(data, size, addr);
}

int AsyncUdpSocket::_add_udp_packet(const char *data, size_t size, const rtc::SocketAddress &addr) {
    // 先尝试主动发送任务队列中的数据，不用靠事件循环触发写事件发送
    size_t len = 0;
    int ret = 0;
    while (!m_udp_packet_list.empty()) {
        // 处理任务队列中的UDP数据包
        UdpPacketData* packet = m_udp_packet_list.front();
        // m_udp_packet_list.pop_front();
        sockaddr_storage addr;
        len = packet->get_addr().ToSockAddrStorage(&addr);
        ret = sock_send_to(m_socket, packet->get_data(), packet->get_size(), MSG_NOSIGNAL, (struct sockaddr*)(&addr), len);
        if (ret < 0) {
            RTC_LOG(LS_WARNING) << "send udp packet error, error: " << strerror(errno) << ", errno: " << errno
                                << ", remote_addr: " << packet->get_addr().ToString();
            delete packet;
            m_udp_packet_list.pop_front();

            return -1;
        } else if (ret == 0) {
            RTC_LOG(LS_WARNING) << "send 0 bytes, try again, remote_addr: " << packet->get_addr().ToString();
            goto SEND_AGAIN;
        } else {
            delete packet;
            m_udp_packet_list.pop_front();
        }
    }

    sockaddr_storage saddr;
    len = addr.ToSockAddrStorage(&saddr);
    ret = sock_send_to(m_socket, data, size, MSG_NOSIGNAL, (struct sockaddr*)(&saddr), len);
    if (ret < 0) {
        RTC_LOG(LS_WARNING) << "send udp packet error, error: " << strerror(errno) << ", errno: " << errno
                            << ", remote_addr: " << addr.ToString();

        return -1;
    } else if (ret == 0) {
        RTC_LOG(LS_WARNING) << "send 0 bytes, try again, remote_addr: " << addr.ToString();
        goto SEND_AGAIN;
    }

    return ret;
    
SEND_AGAIN: 
    UdpPacketData* packet = new UdpPacketData(data, size, addr);
    m_udp_packet_list.push_back(packet);

    // 启动对UDP数据包发送事件的监听
    m_ev->startIOEvent(m_socket_watcher, m_socket, EventLoop::WRITE);

    return size;

} 

} // namespace xrtc